package com.example.haikangdemo.service.impl;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.PreDestroy;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.example.haikangdemo.configuration.HCNetSDK;
import com.example.haikangdemo.service.HaiKangListenService;
import com.sun.jna.Pointer;

import lombok.extern.slf4j.Slf4j;
import static com.example.haikangdemo.service.impl.HaiKangInitServiceImpl.hCNetSDK;

@Slf4j
@Service
public class HaiKangListenServiceImpl implements HaiKangListenService {

    public static HCNetSDK.FMSGCallBack_V31 fmsgCallBack_v31;//设置报警回调函数

    static List<Integer> userId = new ArrayList<>();
    static List<Integer> listen = new ArrayList<>();
    static List<Integer> nativeL = new ArrayList<>();

    @Override
    @Async
    public int deviceRegister(String ip, int port, String userName, String password) {
        //登录设备，每一台设备分别登录; 登录句柄是唯一的，可以区分设备
        //设备登录信息
        HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();
        //设备信息
        HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();
        //设备ip地址
        String m_sDeviceIP = ip;
        m_strLoginInfo.sDeviceAddress = new byte[HCNetSDK.NET_DVR_DEV_ADDRESS_MAX_LEN];
        System.arraycopy(m_sDeviceIP.getBytes(), 0, m_strLoginInfo.sDeviceAddress, 0, m_sDeviceIP.length());
        //设备用户名
        String m_sUsername = userName;
        m_strLoginInfo.sUserName = new byte[HCNetSDK.NET_DVR_LOGIN_USERNAME_MAX_LEN];
        System.arraycopy(m_sUsername.getBytes(), 0, m_strLoginInfo.sUserName, 0, m_sUsername.length());
        //设备密码
        String m_sPassword = password;
        m_strLoginInfo.sPassword = new byte[HCNetSDK.NET_DVR_LOGIN_PASSWD_MAX_LEN];
        System.arraycopy(m_sPassword.getBytes(), 0, m_strLoginInfo.sPassword, 0, m_sPassword.length());
        //SDK端口
        m_strLoginInfo.wPort = (short) port;
        //是否异步登录：0- 否，1- 是
        m_strLoginInfo.bUseAsynLogin = false;
        //ISAPI登录
        m_strLoginInfo.byLoginMode = 0;
        m_strLoginInfo.write();

        int lUserID = hCNetSDK.NET_DVR_Login_V40(m_strLoginInfo, m_strDeviceInfo);
        if (lUserID == -1) {
            log.error("登录失败，错误码为" + hCNetSDK.NET_DVR_GetLastError());
            throw new RuntimeException("登录失败");
        } else {
            System.out.println(hCNetSDK.NET_DVR_GetLastError());
            log.info(
                m_sDeviceIP + ":设备登录成功! " + "设备序列号:" + new String(m_strDeviceInfo.struDeviceV30.sSerialNumber).trim());
            m_strDeviceInfo.read();
            return lUserID;
        }
    }

    @Override
    public void placement(int lUserID) {
        //布防参数
        HCNetSDK.NET_DVR_SETUPALARM_PARAM m_strAlarmInfo = new HCNetSDK.NET_DVR_SETUPALARM_PARAM();
        m_strAlarmInfo.dwSize = m_strAlarmInfo.size();
        //布防等级
        m_strAlarmInfo.byLevel = 1;
        // 智能交通报警信息上传类型：0- 老报警信息（NET_DVR_PLATE_RESULT），1- 新报警信息(NET_ITS_PLATE_RESULT)
        m_strAlarmInfo.byAlarmInfoType = 1;
        //布防类型 0：客户端布防 1：实时布防
        m_strAlarmInfo.byDeployType = 1;
        m_strAlarmInfo.write();
        int nativeLong = hCNetSDK.NET_DVR_SetupAlarmChan_V41(lUserID, m_strAlarmInfo);
        //如果布防失败返回-1
        if (nativeLong < 0) {
            System.out.println("SetupAlarmChan failed, error code=" + hCNetSDK.NET_DVR_GetLastError());
            //注销
            hCNetSDK.NET_DVR_Logout(lUserID);
        }
        //启动监听
        boolean lListenHandle = hCNetSDK.NET_DVR_SetDVRMessageCallBack_V31(fmsgCallBack_v31, null);
        if (!lListenHandle) {
            log.error("启动监听失败，错误号:" + hCNetSDK.NET_DVR_GetLastError());
        } else {
            log.info("==================启动监听成功,等待设备上传报警信息==================");
        }
        userId.add(lUserID);
        nativeL.add(nativeLong);
    }

    @PreDestroy
    public void LogoutAndStopListen() {
        //撤销布防上传通道
        for (int i = 0; i < userId.size(); i++) {
            if (!hCNetSDK.NET_DVR_CloseAlarmChan_V30(nativeL.get(i))) {
                //注销
                hCNetSDK.NET_DVR_Logout(userId.get(i));
            }
        }
        //停止监听 lListenHandle是启动监听时返回值
        for (Integer integer : listen) {
            hCNetSDK.NET_DVR_StopListen_V30(integer);
        }
    }

    @Override
    public void alarmDataHandle(int lCommand, HCNetSDK.NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo, int dwBufLen,
        Pointer pUser) {
        //lCommand是传的报警类型
        switch (lCommand) {
            //人脸比对报警
            case HCNetSDK.COMM_SNAP_MATCH_ALARM:
                HCNetSDK.NET_VCA_FACESNAP_MATCH_ALARM strFaceSnapMatch = new HCNetSDK.NET_VCA_FACESNAP_MATCH_ALARM();
                strFaceSnapMatch.write();
                Pointer pFaceSnapMatch = strFaceSnapMatch.getPointer();
                pFaceSnapMatch.write(0, pAlarmInfo.getByteArray(0, strFaceSnapMatch.size()), 0,
                    strFaceSnapMatch.size());
                strFaceSnapMatch.read();
                // 人脸比对报警图片保存，图片格式URL格式
                if (strFaceSnapMatch.byPicTransType == 1) {
                    log.info("检测到人脸比对事件");
                }
                break;
            case HCNetSDK.COMM_ISAPI_ALARM:
                // 处理安全帽检测上传的照片数据
                HCNetSDK.NET_DVR_ALARM_ISAPI_INFO struEventISAPI = new HCNetSDK.NET_DVR_ALARM_ISAPI_INFO();
                struEventISAPI.write();
                Pointer pEventISAPI = struEventISAPI.getPointer();
                pEventISAPI.write(0, pAlarmInfo.getByteArray(0, struEventISAPI.size()), 0, struEventISAPI.size());
                struEventISAPI.read();

                HCNetSDK.NET_DVR_ALARM_ISAPI_PICDATA struPicData = new HCNetSDK.NET_DVR_ALARM_ISAPI_PICDATA();
                struPicData.write();
                Pointer pPicData = struPicData.getPointer();
                pPicData.write(0, struEventISAPI.pPicPackData.getByteArray(0, struPicData.size()), 0,
                    struPicData.size());
                struPicData.read();
                log.info("检测到安全帽事件");
                break;
            default:
                log.info("报警类型" + Integer.toHexString(lCommand));
                break;
        }
    }
}